package boot.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.*;

@Aspect
@Component
public class APIMonitorAspect {
    // API调用次数统计表
    private final Map<String, Integer> countOfCall = Collections.synchronizedMap(new HashMap<>());

    // API响应时间统计表:存放各个API响应时间
    private final Map<String, List<Long>> timeOfRequest = Collections.synchronizedMap(new HashMap<>());

    // API异常次数统计表
    private final Map<String, Integer> countOfException = Collections.synchronizedMap(new HashMap<>());

    //    @Pointcut("execution(* boot.service..*.*(..))")
//    @Pointcut("execution(* com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.*(..))")
//    @Pointcut("execution(* com.baomidou.mybatisplus.extension.service.IService.*(..))")
    @Pointcut("execution(* com.baomidou.mybatisplus.extension.service..*.*(..))")
    public void servicePointCut() {

    }

    //统计API调用次数
    @Before("servicePointCut()")
    public void calculateCountOfCall(JoinPoint joinPoint) {
        String signatureOfMethod = joinPoint.getSignature().toString();
        if (countOfCall.containsKey(signatureOfMethod)) {
            Integer integer = countOfCall.get(signatureOfMethod);
            countOfCall.replace(signatureOfMethod, integer + 1);
        } else {
            countOfCall.put(signatureOfMethod, 1);
        }
    }

    //统计API响应时间
//    @Around("@within(org.springframework.stereotype.Service)")
//    @Pointcut("execution(* boot.service.impl.* (..))")
    @Around("servicePointCut()")
    public Object calculateTimeOfRequest(ProceedingJoinPoint joinPoint) throws Throwable {
        long t1 = Instant.now().toEpochMilli();
        Object proceed = joinPoint.proceed();
        long t2 = Instant.now().toEpochMilli();
        String signatureOfMethod = joinPoint.getSignature().toString();

//        System.out.println("**************方法被执行**************************************");

        System.out.println();
        //统计API响应时间
        List<Long> list;
        if (!timeOfRequest.containsKey(signatureOfMethod)) {
            list = new ArrayList<>();
            timeOfRequest.put(signatureOfMethod, list);
        } else {
            list = timeOfRequest.get(signatureOfMethod);
        }
        list.add(t2 - t1);
        return proceed;
    }

    //统计API异常次数
    @AfterThrowing(value = "servicePointCut()", throwing = "ex")
    public void calculateCountOfException(JoinPoint jp, Exception ex) {
        String signatureOfMethod = jp.getSignature().toString();
        if (countOfException.containsKey(signatureOfMethod)) {
            Integer integer = countOfException.get(signatureOfMethod);
            countOfException.replace(signatureOfMethod, integer + 1);
        } else {
            countOfException.put(signatureOfMethod, 1);
        }
    }

    //获取各个API的调用次数
    public Map<String, Integer> getCountOfCall() {
        return countOfCall;
    }

    //获取各个API的抛出异常次数
    public Map<String, Integer> getCountOfException() {
        return countOfException;
    }

    //获取各个API的最大响应时间
    public Map<String, Long> getMaxTimeOfRequest() {
        Map<String, Long> maxTimeOfRequest = new HashMap<>();
        List<Long> list;
        for (String s : timeOfRequest.keySet()) {
            list = timeOfRequest.get(s);
            list.sort(Long::compareTo);
            maxTimeOfRequest.put(s, list.get(list.size() - 1));
        }
        return maxTimeOfRequest;
    }

    //获取各个API的最大响应时间
    public Map<String, Long> getMinTimeOfRequest() {
        Map<String, Long> minTimeOfRequest = new HashMap<>();
        List<Long> list;
        for (String s : timeOfRequest.keySet()) {
            list = timeOfRequest.get(s);
            list.sort(Long::compareTo);
            minTimeOfRequest.put(s, list.get(0));
        }
        return minTimeOfRequest;
    }

    //获取各个API的平均响应时间
    public Map<String, Long> getAvgTimeOfRequest() {
        Map<String, Long> avgTimeOfRequest = new HashMap<>();
        List<Long> list;
        long avg;
        for (String s : timeOfRequest.keySet()) {
            list = timeOfRequest.get(s);
            //求平均值
            avg = 0;
            for (Long n : list) {
                avg += n;
            }
            avgTimeOfRequest.put(s, avg / list.size());
        }
        return avgTimeOfRequest;
    }
}
